package com.lastproject.ejb.dao;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.interceptor.Interceptors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import annotations.PermissionAnnotation;

import com.lastproject.dto.WaitingListDTO;
import com.lastproject.ejb.entities.User;
import com.lastproject.ejb.entities.WaitingList;
import com.lastproject.ejb.exceptions.NoPermissionException;
import com.lastproject.ejb.interceptors.PermissionInterceptor;
import com.lastproject.ejb.util.WaitingListConversion;

/**
 * Session Bean implementation class WaitingListDAO author: Lia Sincari
 */
@Stateless
public class WaitingListDAO implements WaitingListDAORemote {

	/**
	 * Default constructor.
	 */
	@PersistenceContext(unitName = "LastProjectEJB")
	private EntityManager em;

	@EJB
	private WaitingListConversion conv;

	public WaitingListDAO() {

	}

	@Interceptors(PermissionInterceptor.class)
	@PermissionAnnotation(canAccessLibrary = 1)
	@Override
	public void create(boolean hasPermission, WaitingListDTO waitingDTO)
			throws NoPermissionException {
		if (!hasPermission) {
			throw new NoPermissionException(
					"WaitingListDAO.create(): You have no permission to add an item on the waiting list!");
		}
		em.persist(conv.fromDTO(waitingDTO));
	}

	@Override
	public void edit(WaitingListDTO waitingDTO) {
		em.merge(conv.fromDTO(waitingDTO));
	}

	@Override
	public void remove(WaitingListDTO waitingDTO) {
		WaitingList wl = em.find(WaitingList.class, conv.fromDTO(waitingDTO)
				.getId());
		em.remove(wl);
	}

	@Override
	public void remove(int bookId, int userId) {
		List<WaitingList> wl = getByUserAndBookIds(bookId, userId);
		em.remove(wl.get(0));
	}

	@Override
	public WaitingListDTO findById(Object id) {

		WaitingList w = em.find(WaitingList.class, id);
		WaitingListDTO wl = conv.fromEntity(w);
		return wl;
	}

	@Override
	public List<WaitingListDTO> getAll() {
		List<WaitingList> waitingList = (List<WaitingList>) em
				.createNamedQuery("WaitingList.findAll", WaitingList.class)
				.getResultList();
		List<WaitingListDTO> waitingDTO = new ArrayList<WaitingListDTO>();

		for (WaitingList w : waitingList) {
			WaitingListDTO wl = new WaitingListDTO();
			wl = conv.fromEntity(w);
			waitingDTO.add(wl);
		}
		return waitingDTO;
	}

	@Override
	public List<WaitingListDTO> getByIdBook(int id) {

		List<WaitingList> waitingList = (List<WaitingList>) em
				.createQuery(
						"SELECT w FROM WaitingList w where w.book.id =:id order by w.emergency desc, w.date desc",
						WaitingList.class).setParameter("id", id)
				.getResultList();
		List<WaitingListDTO> waitingDTO = new ArrayList<WaitingListDTO>();

		for (WaitingList w : waitingList) {
			WaitingListDTO wl = new WaitingListDTO();
			wl = conv.fromEntity(w);
			waitingDTO.add(wl);
		}
		return waitingDTO;
	}

	@Override
	public List<WaitingListDTO> getByIdUserIdBook(int idb, int idu) {
		List<WaitingList> waitingList = getByUserAndBookIds(idb, idu);
		List<WaitingListDTO> waitingDTO = new ArrayList<WaitingListDTO>();

		for (WaitingList w : waitingList) {
			WaitingListDTO wl = new WaitingListDTO();
			wl = conv.fromEntity(w);
			waitingDTO.add(wl);
		}
		return waitingDTO;
	}

	private List<WaitingList> getByUserAndBookIds(int bookId, int userId) {
		return (List<WaitingList>) em
				.createQuery(
						"SELECT w FROM WaitingList w where w.book.id =:idb and w.user.id =:idu ",
						WaitingList.class).setParameter("idb", bookId)
				.setParameter("idu", userId).getResultList();
	}

	@Override
	public boolean getByBookIdOtherUser(int bookId, int userId) {
		List<User> waitingList = (List<User>) em
				.createQuery(
						"Select u from User u where u in "
								+ "(SELECT w.user FROM WaitingList w WHERE w.book.id =:bookId and w.user.id <> :userId) or "
								+ "u in (Select b.user from Borrowed b where b.book.id = :bookId and b.returnDate is null)",
						User.class).setParameter("bookId", bookId)
				.setParameter("userId", userId).getResultList();

		return waitingList.isEmpty();
	}

}
